//
//  ARCExample.swift
//  SwiftCode
//
//  Created by yuhus on 2024/1/3.
//

import Foundation

class ARCExample: ListViewController {
  override func getItemCount() -> Int {
    data.count
  }
  
  override func getItem(_ indexPath: IndexPath) -> Item {
    data[indexPath.row]
  }
  
  private lazy var data: [Item] = [
    .init(title: "自动引用计数实践", description: "自动引用计数实践", action: actionARC),
    .init(title: "弱引用", description: "解决实例之前的循环强引用", action: testWeakReferences),
    .init(title: "闭包的循环强引用", description: "闭包引用了 self 后是如何产生一个循环强引用的", action: testClosure),
  ]
}
//
//private class Person {
//  let name: String
//  
//  init(name: String) {
//    self.name = name
//    print("\(name) is being initialized")
//  }
//  
//  deinit {
//    print("\(name) is being deinitialized")
//  }
//}

// 值会被自动初始化为 nil，目前还不会引用到 Person 类的实例。
private var reference1: Person?
private var reference2: Person?
private var reference3: Person?

private func actionARC() {
  print(">>> 创建 Person 类的新实例，并且将它赋值给三个变量中的一个")
  reference1 = Person(name: "John Appleseed")
  // 打印“John Appleseed is being initialized”
  
  print(">>> 将同一个 Person 实例也赋值给其他两个变量")
  reference2 = reference1
  reference3 = reference1
  
  print(">>> 通过给其中两个变量赋值 nil 的方式断开两个强引用")
  reference1 = nil
  reference2 = nil
  
  print(">>> 第三个也就是最后一个强引用被断开时")
  reference3 = nil
  // 打印“John Appleseed is being deinitialized”
}

// MARK: 弱引用

class Person {
  let name: String
  init(name: String) { self.name = name }
  var apartment: Apartment?
  deinit { print("\(name) is being deinitialized") }
}

class Apartment {
  let unit: String
  init(unit: String) { self.unit = unit }
  weak var tenant: Person?
  deinit { print("Apartment \(unit) is being deinitialized") }
}

var john: Person?
var unit4A: Apartment?

private func testWeakReferences() {
  john = Person(name: "John Appleseed")
  unit4A = Apartment(unit: "4A")
  
  john!.apartment = unit4A
  unit4A!.tenant = john
  
  print(">>> 把 john 变量赋值为 nil 而断开其所保持的强引用，没有指向 Person 实例的强引用了")
  john = nil
  // 打印“John Appleseed is being deinitialized”
  
  print(">>> tenant 属性会被赋值为 nil")
  print(unit4A!.tenant as Any)
  
  print(">>> 把 unit4A 变量赋值为 nil")
  unit4A = nil
  // 打印“Apartment 4A is being deinitialized”
}

// MARK: 闭包的循环强引用

private class HTMLElement {
  let name: String
  let text: String?
  
  lazy var asHTML: () -> String = { [unowned self] in
    if let text = self.text {
      return "<\(self.name)>\(text)</\(self.name)>"
    } else {
      return "<\(self.name) />"
    }
  }
  
  init(name: String, text: String? = nil) {
    self.name = name
    self.text = text
  }
  
  deinit {
    print("\(name) is being deinitialized")
  }
}

/// 实例的 asHTML 属性持有闭包的强引用
/// 闭包在其闭包体内使用了 self
/// 闭包又反过来持有了 HTMLElement 实例的强引用。
private func testClosure() {
  var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
  print(paragraph!.asHTML())
  // 打印“<p>hello, world</p>”
  
  print("设置 paragraph 变量为 nil")
  paragraph = nil
}
